package com.example.basic.web.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.example.basic.exception.ServiceException;
import com.example.basic.utils.HttpUtils;
import com.example.basic.utils.IdUtils;
import com.example.basic.web.enums.DeviceStatusEnum;
import com.example.basic.web.mapper.device.DeviceMapper;
import com.example.basic.web.mapper.newly.SysAdmireMapper;
import com.example.basic.web.mapper.newly.SysFlowTaskMapper;
import com.example.basic.web.mapper.newly.SysPdaFlowMapper;
import com.example.basic.web.model.device.Device;
import com.example.basic.web.model.newly.SysAdmire;
import com.example.basic.web.model.newly.SysFlowTask;
import com.example.basic.web.model.newly.SysPdaFlow;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * 定时任务实现类，包含各种类型的定时任务
 */
@Component
@Slf4j
public class ScheduledTasks {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private SysAdmireMapper sysAdmireMapper;

    @Autowired
    private SysPdaFlowMapper sysPdaFlowMapper;

    @Autowired
    private SysFlowTaskMapper sysFlowTaskMapper;


    /**
     * Cron表达式
     * 这里表示每分钟的第10秒执行一次
     */
    @Scheduled(cron = "10 * * * * *")
    public void task() {
        System.out.println("当前时间: " + dateFormat.format(new Date()));
        //先执行接驳台的缓存
        admireTask();
        //判断火化是否有空闲 如果有空闲的话 就从火化前暂存区发往火化
        cremationTask();
        //判断负一负二提升机是否有空闲,如果有空闲,就从负二担架板缓存发往负一负二提升机
        negativeOneTask();


    }

    /**
     * 从负二担架板缓存区发往负一负二提升机
     * 1.查询所有未使用的负一负二提升机
     * 2.查询最早进入缓存区接驳台的
     * 3.如果有空闲的提升机和正在等待的担架板缓存区 从缓存区发往提升机
     */
    private void negativeOneTask() {
        log.info("开始执行从负二担架板缓存区发往负一负二提升机定时任务");
        // 查询所有使用的负一负二提升机
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, 10); //10负一负二提升机
        queryWrapper.eq(Device::getStatus, DeviceStatusEnum.standby.getType());
        List<Device> standbyDevice = deviceMapper.selectList(queryWrapper);
        if (ObjectUtils.isEmpty(standbyDevice)) {
            return;
        }

        Device standby = standbyDevice.get(0);

        //查询最早进入缓存区接驳台的
        LambdaQueryWrapper<Device> dockQueryWrapper = new LambdaQueryWrapper<>();
        dockQueryWrapper.eq(Device::getDeviceType, 15); //15火化返回提升机前暂存区
        dockQueryWrapper.eq(Device::getStatus, DeviceStatusEnum.work.getType());
        dockQueryWrapper.orderByAsc(Device::getCreateAt);
        dockQueryWrapper.last("limit 1");
        Device dock = deviceMapper.selectOne(dockQueryWrapper);
        if (dock != null) {
            //证明有空闲的提升机 从缓存区发往提升机
            String uuid = IdUtils.fastUUID();
            try {
                SysFlowTask task = new SysFlowTask();
                task.setId(uuid);
                task.setStartPositionId(dock.getId());
                task.setEndPositionId(standby.getId());
                task.setStartStatus(0);
                task.setEndStatus(0);
                task.setCreateAt(new Date());
                task.setUpdateAt(new Date());
                task.setNowStage(11);

                //查询那个yt流程在该位置
                LambdaQueryWrapper<SysPdaFlow> sysPdaFlowLambdaQueryWrapper = new LambdaQueryWrapper<>();
                sysPdaFlowLambdaQueryWrapper.eq(SysPdaFlow::getPositionId, dock.getId());
                SysPdaFlow sysPdaFlow = sysPdaFlowMapper.selectOne(sysPdaFlowLambdaQueryWrapper);

                if (sysPdaFlow != null) {
                    task.setFlowId(sysPdaFlow.getId());
                }
                sysFlowTaskMapper.insert(task);
                HttpUtils.sendPost(null, dock.getDevicePoint(), standby.getDevicePoint(), uuid);

                //将终止位置设为使用中
                LambdaUpdateWrapper<Device> deviceLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                deviceLambdaUpdateWrapper.eq(Device::getId, standby.getId());
                deviceLambdaUpdateWrapper.set(Device::getStatus, DeviceStatusEnum.work.getType());
                deviceLambdaUpdateWrapper.set(Device::getUpdateAt, new Date());
                deviceMapper.update(null, deviceLambdaUpdateWrapper);

                dock.setStatus(DeviceStatusEnum.cache.getType());
                dock.setUpdateAt(new Date());
                deviceMapper.updateById(dock);
            } catch (Exception e) {
                throw new ServiceException("调度失败请联系管理员");
            }
        }
    }

    private void cremationTask() {
        log.info("开始执行火化前缓存到火化任务");
        // 查询所有使用的火化间
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, 7); //7火化

        queryWrapper.eq(Device::getStatus, DeviceStatusEnum.standby.getType());
        List<Device> standbyDevice = deviceMapper.selectList(queryWrapper);

        if (ObjectUtils.isEmpty(standbyDevice)) {
            return;
        }

        Device device = standbyDevice.get(0);
        //查询最早进入缓存区接驳台的
        LambdaQueryWrapper<Device> dockQueryWrapper = new LambdaQueryWrapper<>();
        dockQueryWrapper.eq(Device::getDeviceType, 14); //14火化前缓存区
        dockQueryWrapper.eq(Device::getStatus, DeviceStatusEnum.work.getType());
        dockQueryWrapper.orderByAsc(Device::getCreateAt);
        dockQueryWrapper.last("limit 1");
        Device dock = deviceMapper.selectOne(dockQueryWrapper);
        if (dock != null) {
            //证明有空闲的火化间 从缓存区发往火化间
            String uuid = IdUtils.fastUUID();
            try {
                SysFlowTask task = new SysFlowTask();
                task.setId(uuid);
                task.setStartPositionId(dock.getId());
                task.setEndPositionId(device.getId());
                task.setStartStatus(0);
                task.setEndStatus(0);
                task.setCreateAt(new Date());
                task.setUpdateAt(new Date());
                task.setNowStage(8);

                //查询那个yt流程在该位置
                LambdaQueryWrapper<SysPdaFlow> sysPdaFlowLambdaQueryWrapper = new LambdaQueryWrapper<>();
                sysPdaFlowLambdaQueryWrapper.eq(SysPdaFlow::getPositionId, dock.getId());
                SysPdaFlow sysPdaFlow = sysPdaFlowMapper.selectOne(sysPdaFlowLambdaQueryWrapper);

                if (sysPdaFlow != null) {
                    task.setFlowId(sysPdaFlow.getId());
                }

                sysFlowTaskMapper.insert(task);
                HttpUtils.sendPost(null, dock.getDevicePoint(), device.getDevicePoint(), uuid);
                //然后将其实和终止都设为使用中

                device.setStatus(DeviceStatusEnum.work.getType());
                device.setUpdateAt(new Date());
                deviceMapper.updateById(device);

                dock.setStatus(DeviceStatusEnum.cache.getType());
                dock.setUpdateAt(new Date());
                deviceMapper.updateById(dock);

            } catch (IOException e) {
                throw new ServiceException("调度失败请联系管理员");
            }
        }
    }

    public void admireTask() {
        log.info("开始执行瞻仰厅接驳台到瞻仰厅任务");
        // 查询所有使用的瞻仰前接驳台
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, 13); //13瞻仰前缓存区
        queryWrapper.eq(Device::getStatus, DeviceStatusEnum.work.getType());
        List<Device> usedDockStations = deviceMapper.selectList(queryWrapper);
        log.info("查出共有{}个使用中的瞻仰前接驳台", usedDockStations.size());
        for (Device usedDockStation : usedDockStations) {
            LambdaQueryWrapper<SysAdmire> admireQueryWrapper = new LambdaQueryWrapper<>();
            admireQueryWrapper.eq(SysAdmire::getCachePositionId, usedDockStation.getId());
            SysAdmire sysAdmire = sysAdmireMapper.selectOne(admireQueryWrapper);
            Device device = deviceMapper.selectById(sysAdmire.getId());
            log.info("根据瞻仰接驳台id为{},查询到的瞻仰厅id为{}", usedDockStation.getId(),device.getId());

            if (device.getStatus().equals(DeviceStatusEnum.standby.getType())) {
                //证明对应的瞻仰厅已经空闲,可以发往瞻仰厅 查询处于该接驳台的yt
                LambdaQueryWrapper<SysPdaFlow> flowQueryWrapper = new LambdaQueryWrapper<>();
                flowQueryWrapper.eq(SysPdaFlow::getPositionId, usedDockStation.getId());
                SysPdaFlow sysPdaFlow = sysPdaFlowMapper.selectOne(flowQueryWrapper);

                if (sysPdaFlow != null) {
                    log.info("根据瞻仰前接驳台id为{},查询到的流程id为{}", usedDockStation.getId(),sysPdaFlow.getId());
                    //证明有对应的yt 从接驳台发往瞻仰厅
                    String uuid = IdUtils.fastUUID();
                    try {
                        SysFlowTask task = new SysFlowTask();
                        task.setId(uuid);
                        task.setFlowId(sysPdaFlow.getId());
                        task.setStartPositionId(usedDockStation.getId());
                        task.setEndPositionId(sysAdmire.getId());
                        task.setStartStatus(0);
                        task.setEndStatus(0);
                        task.setCreateAt(new Date());
                        task.setUpdateAt(new Date());
                        task.setNowStage(7);
                        sysFlowTaskMapper.insert(task);

                        HttpUtils.sendPost(null, usedDockStation.getDevicePoint(), device.getDevicePoint(), uuid);
                        log.info("瞻仰发送的任务从{}到{}", usedDockStation.getDevicePoint(), device.getDevicePoint());

                        //终止都设为使用中
                        LambdaUpdateWrapper<Device> deviceLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                        deviceLambdaUpdateWrapper.eq(Device::getId, sysAdmire.getId());
                        deviceLambdaUpdateWrapper.set(Device::getStatus, DeviceStatusEnum.work.getType());
                        deviceLambdaUpdateWrapper.set(Device::getUpdateAt, new Date());
                        deviceMapper.update(null, deviceLambdaUpdateWrapper);
                    } catch (IOException e) {
                        throw new ServiceException("调度失败请联系管理员");
                    }
                }
            }
        }
    }



    /**
     * 担架板缓存只有一个,所以说从负一负二提升机发往担架板缓存的可能会卡住,所以需要定时任务来检查是否有空闲的担架板缓存,然后将负一负二卡住的发往担架板缓存
     * 从负一负二提升机发往担架板缓存
     * 前提为火化完毕,流程位置处于负一负二提升机,即可确定下一步是往担架板缓存发送的
     */
    @Scheduled(cron = "30 * * * * *")
    public void elevatorToDj() {
        log.info("开始执行从负一负二提升机发往担架板中转任务");
        //先查询担架板缓存是否空闲
        LambdaQueryWrapper<Device> dockQueryWrapper = new LambdaQueryWrapper<>();
        dockQueryWrapper.eq(Device::getDeviceType, 12);
        dockQueryWrapper.eq(Device::getStatus, DeviceStatusEnum.standby.getType());
        List<Device> dockList = deviceMapper.selectList(dockQueryWrapper);

        if (ObjectUtils.isEmpty(dockList)) {
            return;
        }

        Device dock = dockList.get(0);
        //查出负一负二被占用超过五分钟的设备
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, 10); //10负一负二提升机
        queryWrapper.eq(Device::getStatus, DeviceStatusEnum.work.getType());
        queryWrapper.le(Device::getUpdateAt, new Date(System.currentTimeMillis() - 2 * 60 * 1000));
        queryWrapper.orderByAsc(Device::getUpdateAt);
        queryWrapper.last("limit 1");
        Device device = deviceMapper.selectOne(queryWrapper);
        if (ObjectUtils.isNotEmpty(device)) {
            LambdaQueryWrapper<SysPdaFlow> flowQueryWrapper = new LambdaQueryWrapper<>();
            //火化时间小于当前时间
            flowQueryWrapper.le(SysPdaFlow::getFireTime, new Date());
            flowQueryWrapper.eq(SysPdaFlow::getPositionId, device.getId());
            SysPdaFlow sysPdaFlow = sysPdaFlowMapper.selectOne(flowQueryWrapper);
            if (ObjectUtils.isNotEmpty(sysPdaFlow)) {
                //证明有对应的y流程 从提升机发往担架板中转
                String uuid = IdUtils.fastUUID();
                try {
                    SysFlowTask task = new SysFlowTask();
                    task.setId(uuid);
                    task.setFlowId(sysPdaFlow.getId());
                    task.setStartPositionId(device.getId());
                    task.setEndPositionId(dock.getId());
                    task.setStartStatus(0);
                    task.setEndStatus(0);
                    task.setCreateAt(new Date());
                    task.setUpdateAt(new Date());
                    task.setNowStage(12);
                    sysFlowTaskMapper.insert(task);

                    HttpUtils.sendPost(null, device.getDevicePoint(), dock.getDevicePoint(), uuid);
                    //终止都设为使用中
                    LambdaUpdateWrapper<Device> deviceLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    deviceLambdaUpdateWrapper.eq(Device::getId, dock.getId());
                    deviceLambdaUpdateWrapper.set(Device::getStatus, DeviceStatusEnum.work.getType());
                    deviceLambdaUpdateWrapper.set(Device::getUpdateAt, new Date());
                    deviceMapper.update(null, deviceLambdaUpdateWrapper);

                    device.setStatus(DeviceStatusEnum.cache.getType());
                    device.setUpdateAt(new Date());
                    deviceMapper.updateById(device);

                } catch (Exception e) {
                    throw new ServiceException("调度失败请联系管理员");
                }
            }
        }

    }

    /**
     * 火化完之后担架板到达担架板中转区域   但是担架板库出现了被占满的情况,就会卡死在担架板中转区域,
     * 需要定时任务来检查是否有空闲的担架板库,然后将卡住的发往担架板库
     */
    @Scheduled(cron = "50 * * * * *")
    public void djTask(){

        //查询是否有空闲的担架板库
        LambdaQueryWrapper<Device> deviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        deviceLambdaQueryWrapper.eq(Device::getDeviceType, 11); //11担架板
        deviceLambdaQueryWrapper.eq(Device::getStatus, DeviceStatusEnum.standby.getType());
        List<Device> standbyDevice = deviceMapper.selectList(deviceLambdaQueryWrapper);

        if (ObjectUtils.isEmpty(standbyDevice)) {
            return;
        }
        //获取一个空闲的担架板库位
        Device standby = standbyDevice.get(0);

        //查询是否有卡在担架板中转的
        LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Device::getDeviceType, 12); //12担架板中转
        queryWrapper.eq(Device::getStatus, DeviceStatusEnum.work.getType());
        queryWrapper.le(Device::getUpdateAt, new Date(System.currentTimeMillis() - 2 * 60 * 1000));
        queryWrapper.orderByAsc(Device::getUpdateAt);
        queryWrapper.last("limit 1");
        Device device = deviceMapper.selectOne(queryWrapper);
        if (ObjectUtils.isNotEmpty(device)) {
            LambdaQueryWrapper<SysPdaFlow> flowQueryWrapper = new LambdaQueryWrapper<>();
            //火化时间小于当前时间
            flowQueryWrapper.le(SysPdaFlow::getFireTime, new Date());
            flowQueryWrapper.eq(SysPdaFlow::getPositionId, device.getId());
            SysPdaFlow sysPdaFlow = sysPdaFlowMapper.selectOne(flowQueryWrapper);

            if (ObjectUtils.isNotEmpty(sysPdaFlow)) {
                //证明有对应的y流程 从提升机发往担架板中转
                String uuid = IdUtils.fastUUID();
                try {
                    SysFlowTask task = new SysFlowTask();
                    task.setId(uuid);
                    task.setFlowId(sysPdaFlow.getId());
                    task.setStartPositionId(device.getId());
                    task.setEndPositionId(standby.getId());
                    task.setStartStatus(0);
                    task.setEndStatus(0);
                    task.setCreateAt(new Date());
                    task.setUpdateAt(new Date());
                    task.setNowStage(14);
                    sysFlowTaskMapper.insert(task);

                    HttpUtils.sendPost(null, device.getDevicePoint(), standby.getDevicePoint(), uuid);

                    //终止都设为使用中
                    LambdaUpdateWrapper<Device> deviceLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                    deviceLambdaUpdateWrapper.eq(Device::getId, standby.getId());
                    deviceLambdaUpdateWrapper.set(Device::getStatus, DeviceStatusEnum.work.getType());
                    deviceLambdaUpdateWrapper.set(Device::getUpdateAt, new Date());
                    deviceMapper.update(null, deviceLambdaUpdateWrapper);

                    device.setStatus(DeviceStatusEnum.cache.getType());
                    device.setUpdateAt(new Date());
                    deviceMapper.updateById(device);

                } catch (Exception e) {
                    throw new ServiceException("调度失败请联系管理员");
                }
            }
        }
    }

}
